package com.lam.framework.datasource.aop;

import java.util.Objects;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.lam.framework.datasource.JdbcContextHolder;
import com.lam.framework.datasource.annotation.DS;

/**
 * @author lam
 *
 */
@Aspect
@Order(Ordered.LOWEST_PRECEDENCE-1)	//设置AOP执行顺序(需要在事务之前，否则事务只发生在默认库中)
@Component
public class DataSourceAspect {
	
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	//切点 
	@Pointcut("execution(* com.lam..*.service..*.*(..)) &&@annotation(com.lam.framework.datasource.annotation.DS)")
	public void aspect() { }
	
	@Around("aspect()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    	//获取方法的参数
    	Object[] args = joinPoint.getArgs();
    	DS ds = getAnnotation(joinPoint);
        if (ds != null) {
            JdbcContextHolder.putDataSource(ds.value());
            logger.debug("动态切换数据源:{}", ds.value());
        }
        
        Object object;
		try {
			object = joinPoint.proceed(args);
		} catch (Throwable e) {
			logger.error(e.getMessage(), e);
			throw e;
		}finally {
			// 在执行方法之后 销毁数据源 
			JdbcContextHolder.clearDataSource();
		}
		return object;
	}
	
	/**
	 * 获取需要切换的数据源
	 */
	private DS getAnnotation(ProceedingJoinPoint point) {
		MethodSignature signature = (MethodSignature) point.getSignature();
		DS ds = AnnotationUtils.findAnnotation(signature.getMethod(), DS.class);
		if (Objects.nonNull(ds)) {
			return ds;
		}

		return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DS.class);
	}
}
